//R-Type (Opcode 000000)
/*
`define OPCODE_ADD     6'b000000
`define OPCODE_SUB     6'b000000
`define OPCODE_ADDU    6'b000000
`define OPCODE_SUBU    6'b000000
`define OPCODE_AND     6'b000000
`define OPCODE_OR      6'b000000
`define OPCODE_SLL     6'b000000
`define OPCODE_SRA     6'b000000
`define OPCODE_SRL     6'b000000
`define OPCODE_SLT     6'b000000
`define OPCODE_SLTU    6'b000000
`define OPCODE_SUB     6'b000000
*/

//Consolidation of RTypeFunctions
`define RTYPEOPCODE	   6'b000000

//I-Type (All opcodes except 000000, 00001x, and 0100xx)
`define OPCODE_ADDI    6'b001000
`define OPCODE_ADDIU   6'b001001	
`define OPCODE_ANDI    6'b001100
`define OPCODE_BEQ     6'b000100
`define OPCODE_BNE     6'b000101
`define OPCODE_BLEZ    6'b000110
`define OPCODE_BLTZ    6'b000001
`define OPCODE_ORI     6'b001101
`define OPCODE_XORI    6'b001110
`define OPCODE_NOP     6'b110110
`define OPCODE_LUI     6'b001111
`define OPCODE_SLTI    6'b001010
`define OPCODE_SLTIU   6'b001011
`define OPCODE_LW      6'b100011
`define OPCODE_SW      6'b101011

// J-Type (Opcode 00001x)
`define OPCODE_J       6'b000010
`define OPCODE_JAL     6'b000011

/*
`define ADD  4'b0111 // 2's compl add
`define ADDU 4'b0001 // unsigned add
`define SUB  4'b0010 // 2's compl subtract
`define SUBU 4'b0011 // unsigned subtract
`define AND  4'b0100 // bitwise OR
`define OR   4'b0101 // bitwise AND
`define XOR  4'b0110 // bitwise XOR
`define SLT  4'b1010 // set result=1 if less than 2's compl
`define SLTU 4'b1011 // set result=1 if less than unsigned
`define NOP  4'b0000 // do nothing
`define LUI  4'b1110
`define SRA  4'b1101
`define SLL  4'b1100
`define SRL  4'b1001
`define FUNC 4'b1111
*/

module PipelinedControl(RegDst, ALUSrc, MemToReg, RegWrite, MemRead, MemWrite, Branch, Jump, SignExtend, ALUOp, RegClear, Opcode, CLK, Bubble);
   input [5:0] Opcode;
   input Bubble;
   input CLK;
   
   output RegClear;
   output RegDst;
   output ALUSrc;
   output MemToReg;
   output RegWrite;
   output MemRead;
   output MemWrite;
   output Branch;
   output Jump;
   output SignExtend;
   output [3:0] ALUOp;
	 
	reg	RegClear, RegDst, ALUSrc, MemToReg, RegWrite, MemRead, MemWrite, Branch, Jump, SignExtend;
	reg  [3:0] ALUOp;
	always @ (negedge CLK or Opcode or Bubble) begin
		if(Bubble) begin
			RegClear <= #2 1'bX;
			RegDst <= #2 1'bX;
			ALUSrc <= #2 1'bX;
			MemToReg <= #2 1'bX;
			RegWrite <= #2 1'bX;
			MemRead <= #2 1'bX;
			MemWrite <= #2 1'bX;
			Branch <= #2 1'bX;
			Jump <= #2 1'bX;
			SignExtend <= #2 1'bX;
			ALUOp <= #2 `NOP;
			end
		else begin
			case(Opcode)
				`RTYPEOPCODE: begin
					RegClear <= #2 0;
					RegDst <= #2 1;
					ALUSrc <= #2 0;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 1'bX;
					ALUOp <= #2 `FUNC;
				end
				`OPCODE_BNE: begin
					RegClear <= #2 0;
					RegDst <= #2 1'bX;
					ALUSrc <= #2 0;
					MemToReg <= #2 1'bX;
					RegWrite <= #2 0;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 1;
					Jump <= #2 1'bX;
					SignExtend <= #2 1'bx;
					ALUOp <= #2 `SUB;
				end
				`OPCODE_BLEZ: begin
					RegClear <= #2 0;
					RegDst <= #2 1'bX;
					ALUSrc <= #2 0;
					MemToReg <= #2 1'bX;
					RegWrite <= #2 0;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 1;
					Jump <= #2 1'bX;
					SignExtend <= #2 1'bX;
					ALUOp <= #2 `NOP;
				end
				`OPCODE_BLTZ: begin
					RegClear <= #2 0;
					RegDst <= #2 1'bX;
					ALUSrc <= #2 0;
					MemToReg <= #2 1'bX;
					RegWrite <= #2 0;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 1;
					Jump <= #2 1'bX;
					SignExtend <= #2 1'bX;
					ALUOp <= #2 `NOP;
				end
				`OPCODE_ORI: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 0;
					ALUOp <= #2 `OR;
				end
				`OPCODE_LUI: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 0;
					ALUOp <= #2 `LUI;
				end
				`OPCODE_ADDI: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 1;
					ALUOp <= #2 `ADD;
				end
				`OPCODE_ADDIU: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 1;
					ALUOp <= #2 `ADDU;
				end
				`OPCODE_ANDI: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 0;
					ALUOp <= #2 `AND;
				end
				`OPCODE_XORI: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 0;
					ALUOp <= #2 `XOR;
				end
				`OPCODE_SLTI: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 1;
					ALUOp <= #2 `SLT;
				end
				`OPCODE_SLTIU: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 0;
					ALUOp <= #2 `SLTU;
				end
				`OPCODE_LW: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 1;
					MemToReg <= #2 1;
					RegWrite <= #2 1;
					MemRead <= #2 1;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 1;
					ALUOp <= #2 `ADD;
				end
				`OPCODE_SW: begin
					RegClear <= #2 0;
					RegDst <= #2 1'bX;
					ALUSrc <= #2 1;
					MemToReg <= #2 1'bX;
					RegWrite <= #2 0;
					MemRead <= #2 0;
					MemWrite <= #2 1;
					Branch <= #2 0;
					Jump <= #2 0;
					SignExtend <= #2 1;
					ALUOp <= #2 `ADD;
				end
				`OPCODE_BEQ: begin
					RegClear <= #2 0;
					RegDst <= #2 1'bX;
					ALUSrc <= #2 0;
					MemToReg <= #2 1'bX;
					RegWrite <= #2 0;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 1;
					Jump <= #2 0;
					SignExtend <= #2 1;
					ALUOp <= #2 `SUB;
				end
				`OPCODE_J: begin
					RegClear <= #2 0;
					RegDst <= #2 1'bX;
					ALUSrc <= #2 1'bX;
					MemToReg <= #2 1'bX;
					RegWrite <= #2 1'b0;
					MemRead <= #2 1'b0;
					MemWrite <= #2 1'b0;
					Branch <= #2 1'bX;
					Jump <= #2 1;
					SignExtend <= #2 1'b0;
					ALUOp <= #2`NOP;
				end
				`OPCODE_JAL: begin
					RegClear <= #2 0;
					RegDst <= #2 0;
					ALUSrc <= #2 0;
					MemToReg <= #2 0;
					RegWrite <= #2 1;
					MemRead <= #2 0;
					MemWrite <= #2 0;
					Branch <= #2 0;
					Jump <= #2 1;
					SignExtend <= #2 0;
					ALUOp <= #2`NOP;
				end
				`OPCODE_NOP: begin
					RegClear <= #2 1;
					RegDst <= #2 1'bX;
					ALUSrc <= #2 1'bX;
					MemToReg <= #2 1'bX;
					RegWrite <= #2 1'bX;
					MemRead <= #2 1'bX;
					MemWrite <= #2 1'bX;
					Branch <= #2 1'bX;
					Jump <= #2 1'bX;
					SignExtend <= #2 1'bX;
					ALUOp <= #2 `NOP;
				end
				default: begin
					RegClear <= #2 0;
					RegDst <= #2 1'bX;
					ALUSrc <= #2 1'bX;
					MemToReg <= #2 1'bX;
					RegWrite <= #2 1'bX;
					MemRead <= #2 1'bX;
					MemWrite <= #2 1'bX;
					Branch <= #2 1'bX;
					Jump <= #2 1'bX;
					SignExtend <= #2 1'bX;
					ALUOp <= #2 4'bXXXX;
				end
			endcase
		end
		$display($time, "Pipelined Control: ALUOp=%b, Opcode=%b Bubble=%b", ALUOp, Opcode,Bubble);
	end
endmodule
